/*
 * Copyright (C) 2009 Jiannan Lu
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.restsql;

import com.restsql.atom.util.CollectionUtil;
import com.restsql.atom.util.EntryUtil;
import com.restsql.atom.util.FeedUtil;
import com.restsql.db.Database;
import com.restsql.db.sql.InvalidInputDataException;
import com.restsql.db.sql.SQLDesigner;
import com.restsql.http.HTTPMethod;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import restsql.Main;


/**
 *
 * @author jiann.lu@yahoo.com
 */
public class RestSQLHttpServerHandler implements HttpHandler {

    Database db;
    SQLDesigner designer;
    Boolean _isEntryType;
    
    public RestSQLHttpServerHandler(Database database) {
        db = database;
        designer = db.getSQLDesigner();
    }

    public void handle(HttpExchange httpExchange) throws IOException {
        URI uri = httpExchange.getRequestURI();
        System.out.println(uri.getPath());
        _isEntryType = isEntryType(uri.getPath());
        final OutputStream os = httpExchange.getResponseBody();
        String httpresponse = "";
        try {
            httpresponse = buildResponse(httpExchange);
        } catch (SQLException ex) {
            Logger.getLogger(RestSQLHttpServerHandler.class.getName()).log(Level.SEVERE, null, ex);
            if(ex.getErrorCode()<0){
                httpresponse = HttpURLConnection.HTTP_NO_CONTENT+":"+ex.getMessage();
            }
            else{
                httpresponse = HttpURLConnection.HTTP_INTERNAL_ERROR+":"+ex.getMessage();
            }
            httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_INTERNAL_ERROR, httpresponse.length());
        } catch (InvalidInputDataException ex) {
            Logger.getLogger(RestSQLHttpServerHandler.class.getName()).log(Level.SEVERE, null, ex);
            httpresponse = HttpURLConnection.HTTP_NOT_FOUND+":"+"HTTP_NOT_FOUND";
            httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_NOT_FOUND, httpresponse.length());
        } catch (Exception ex) {
            Logger.getLogger(RestSQLHttpServerHandler.class.getName()).log(Level.SEVERE, null, ex);
            httpresponse = HttpURLConnection.HTTP_INTERNAL_ERROR+":"+"HTTP_INTERNAL_ERROR";
            httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_INTERNAL_ERROR, httpresponse.length());
        }
        finally{
            os.write(httpresponse.getBytes());
            os.close();
        }

    }

    /**
     * Build a String to return to the web browser via an HTTP response.
     *
     * @return String for HTTP response.
     */
    private String buildResponse(HttpExchange httpExchange) throws SQLException, InvalidInputDataException, UnsupportedEncodingException, IOException, Exception {
        String httpresponse = "";
        if (httpExchange.getRequestMethod().equals(HTTPMethod.GET)) {
            String path = httpExchange.getRequestURI().getPath();
            if(path.indexOf("crossdomain.xml")>0){
                httpresponse = "<?xml version=\"1.0\"?><!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">" +
                        "<cross-domain-policy><allow-access-from domain=\"*\" /><allow-http-request-headers-from domain=\"*\" headers=\"*\"/>" +
                        "</cross-domain-policy>";
                httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, httpresponse.length());
            }
            else if(path.matches("\\/")){
                httpresponse = CollectionUtil.TablesToCollection(db);  
                httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, httpresponse.length());
            }else{
                designer.parseForGet(httpExchange);
                ResultSet rs = db.getResultSet(designer.getSelectSQL());
                if(_isEntryType){
                    httpresponse = EntryUtil.DataToEntry(rs, httpExchange,db);
                }else{
                    httpresponse = FeedUtil.DataToFeed(rs, httpExchange,db);
                }
                if(httpresponse.isEmpty()){
                    httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_NOT_FOUND, httpresponse.length());
                }
                else{
                    
                    httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, httpresponse.length());
                }
            }
        }
        else if(httpExchange.getRequestMethod().equals(HTTPMethod.POST)){
            designer.parseForPost(httpExchange);
            String key = db.setNew_geneKey(designer.getInsertSQL());
            httpresponse = Main.HOST_URL+httpExchange.getRequestURI().toString()+"("+key+")";
            httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_CREATED, httpresponse.length());
        }
        else if(httpExchange.getRequestMethod().equals(HTTPMethod.PUT)){
            designer.parseForPut(httpExchange);
            int row_count = db.set(designer.getUpdateSQL());
            if(row_count>0){
                httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, httpresponse.length());
            }
            return "HTTPMethod.PUT";
        }
        else if(httpExchange.getRequestMethod().equals(HTTPMethod.DELETE)){
            designer.parseForDelete(httpExchange);
             int row_count = db.delete(designer.getDeleteSQL());
            if(row_count>0){
                httpExchange.sendResponseHeaders(HttpURLConnection.HTTP_OK, httpresponse.length());
            }
            return "HTTPMethod.DELETE";
        }
        return httpresponse;
    }

    private boolean isEntryType(String uriPath){
            Pattern patternfilter = Pattern.compile(">=|<=|=|>|<");
            Matcher matcherfilter = patternfilter.matcher(uriPath);
        return (uriPath.split("\\/").length==2&&uriPath.split("\\(.*?\\)").length==1&&!(matcherfilter.find())&&uriPath.endsWith(")"));
    }
}
